from tensorflow import keras, losses
import pandas as pd
import tensorflow as tf  # 导入 TF 库

from pdf.NetWork import Network

if __name__ == '__main__':
    dataset_path = keras.utils.get_file("auto-mpg.data",
                                        "http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")
    column_names = ['MPG', 'Cylinders', 'Displacement', 'Horsepower', 'Weight',
                    'Acceleration', 'Model Year', 'Origin']
    raw_dataset = pd.read_csv(dataset_path, names=column_names,
                              na_values="?", comment='\t',
                              sep=" ", skipinitialspace=True)
    dataset = raw_dataset.copy()
    dataset.head()  # 查看部分数据
    dataset.isna().sum()  # 统计空白数据
    dataset = dataset.dropna()  # 删除空白数据项
    dataset.isna().sum()  # z再次统计空白数据
    # 处理类别型数据，其中 origin 列代表了类别 1,2,3,分布代表产地：美国、欧洲、日本
    # 先弹出(删除并返回)origin 这一列
    origin = dataset.pop('Origin')
    dataset['USA'] = (origin == 1) * 1.0
    dataset['Europe'] = (origin == 2) * 1.0
    dataset['Japan'] = (origin == 3) * 1.0
    dataset.tail()  # 查看新表格的后几项
    # 切分为训练集和测试集
    train_dataset = dataset.sample(frac=0.8, random_state=0)
    test_dataset = dataset.drop(train_dataset.index)
    # 移动 MPG 油耗效能这一列为真实标签 Y
    train_labels = train_dataset.pop('MPG')
    test_labels = test_dataset.pop('MPG')
    # 查看训练集的输入 X 的统计数据
    train_stats = train_dataset.describe()
    # train_stats.pop("MPG")  # 仅保留输入 X
    train_stats = train_stats.transpose()  # 转置


    # 标准化数据
    def norm(x):  # 减去每个字段的均值，并除以标准差
        return (x - train_stats['mean']) / train_stats['std']


    normed_train_data = norm(train_dataset)  # 标准化训练集
    normed_test_data = norm(test_dataset)  # 标准化测试集
    print(normed_train_data.shape, train_labels.shape)
    print(normed_test_data.shape, test_labels.shape)
    train_db = tf.data.Dataset.from_tensor_slices((normed_train_data.values,
                                                   train_labels.values))  # 构建 Dataset 对象
    train_db = train_db.shuffle(100).batch(32)  # 随机打散，批量化

    train_db = tf.data.Dataset.from_tensor_slices((normed_train_data.values,
                                                   train_labels.values))  # 构建 Dataset 对象
    train_db = train_db.shuffle(100).batch(32)  # 随机打散，批量化

    # 6.8.3
    model = Network()  # 创建网络类实例
    # 通过 build 函数完成内部张量的创建，其中 4 为任意设置的 batch 数量，9 为输入特征长度
    model.build(input_shape=(4, 9))
    model.summary()  # 打印网络信息
    optimizer = tf.keras.optimizers.RMSprop(0.001)  # 创建优化器，指定学习率
    for epoch in range(200):
        for step, (x, y) in enumerate(train_db):  # 遍历一遍训练集
            # 梯度记录器，训练时需要使用它
            with tf.GradientTape() as tape:
                out = model(x)
                loss = tf.reduce_mean(losses.MSE(y, out))  # 计算MSE
                mae_loss = tf.reduce_mean(losses.MAE(y, out))  # 计算MAE
            if step % 10 == 0:  # 间隔性打印训练误差
                print(epoch, step, float(loss))
            # 计算梯度，并更新
            grads = tape.gradient(loss, model.trainable_variables)
            optimizer.apply_gradients(zip(grads, model.trainable_variables))

